package me.hetong.caigou.util;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import me.hetong.caigou.entity.Chess;
import me.hetong.caigou.entity.Zhao;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * FEN 转化工具类
 *
 * @author hetong
 */
public class FenUtils {
    public static final String ORIGIN_FEN = "rnbakabnr/9/1c5c1/p1p1p1p1p/9/9/P1P1P1P1P/1C5C1/9/RNBAKABNR";
    public static final Map<String, String> map = new HashMap<>();

    static {
        map.put("r", "{\"name\": \"车\", \"k\": \"r\", \"type\": \"b\"}");
        map.put("n", "{\"name\": \"马\", \"k\": \"n\", \"type\": \"b\"}");
        map.put("b", "{\"name\": \"象\", \"k\": \"b\", \"type\": \"b\"}");
        map.put("a", "{\"name\": \"士\", \"k\": \"a\", \"type\": \"b\"}");
        map.put("k", "{\"name\": \"将\", \"k\": \"k\", \"type\": \"b\"}");
        map.put("c", "{\"name\": \"砲\", \"k\": \"c\", \"type\": \"b\"}");
        map.put("p", "{\"name\": \"卒\", \"k\": \"p\", \"type\": \"b\"}");
        map.put("P", "{\"name\": \"兵\", \"k\": \"P\", \"type\": \"w\"}");
        map.put("C", "{\"name\": \"炮\", \"k\": \"C\", \"type\": \"w\"}");
        map.put("R", "{\"name\": \"车\", \"k\": \"R\", \"type\": \"w\"}");
        map.put("N", "{\"name\": \"马\", \"k\": \"N\", \"type\": \"w\"}");
        map.put("B", "{\"name\": \"相\", \"k\": \"B\", \"type\": \"w\"}");
        map.put("A", "{\"name\": \"仕\", \"k\": \"A\", \"type\": \"w\"}");
        map.put("K", "{\"name\": \"帅\", \"k\": \"K\", \"type\": \"w\"}");

        map.put("１", "1");
        map.put("２", "2");
        map.put("３", "3");
        map.put("４", "4");
        map.put("５", "5");
        map.put("６", "6");
        map.put("７", "7");
        map.put("８", "8");
        map.put("９", "9");
        map.put("0", "０");
        map.put("1", "１");
        map.put("2", "２");
        map.put("3", "３");
        map.put("4", "４");
        map.put("5", "５");
        map.put("6", "６");
        map.put("7", "７");
        map.put("8", "８");
        map.put("9", "９");
        map.put("8x", "一");
        map.put("7x", "二");
        map.put("6x", "三");
        map.put("5x", "四");
        map.put("4x", "五");
        map.put("3x", "六");
        map.put("2x", "七");
        map.put("1x", "八");
        map.put("0x", "九");
        map.put("1y", "一");
        map.put("2y", "二");
        map.put("3y", "三");
        map.put("4y", "四");
        map.put("5y", "五");
        map.put("6y", "六");
        map.put("7y", "七");
        map.put("8y", "八");
        map.put("9y", "九");
        map.put("space", "　");
    }

    /**
     * 将FEN字符串转换为棋子列表
     *
     * @param fenStr FEN字符串
     * @return List<Chess>
     */
    public static List<Chess> fenToChessList(String fenStr) {
        if (StrUtil.isBlank(fenStr)) {
            fenStr = ORIGIN_FEN;
        }
        List<Chess> chessList = new ArrayList<>();
        // 将字符串分隔成行
        String[] lines = fenStr.split("/");
        // 处理每一行
        for (int y = 0; y < lines.length; y++) {
            // x从0开始
            int x = 0;
            // y就是循环的行号,此时拿到这一行的所有fen字符串
            String line = lines[y];
            for (int j = 0; j < line.length(); j++) {
                char c = line.charAt(j);
                boolean digit = Character.isDigit(c);
                if (digit) {
                    // 是数字
                    x += Integer.parseInt(String.valueOf(c));
                } else {
                    // 是字母,即表示当前是个棋子
                    String s = map.get(String.valueOf(c));
                    Chess chess = JSONUtil.toBean(s, Chess.class);
                    chess.setX(x);
                    chess.setY(y);
                    chessList.add(chess);
                    x++;
                }
            }
        }
        return chessList;
    }

    /**
     * 将棋子列表转换为FEN字符串
     *
     * @param chessList 棋子列表
     * @return FEN字符串
     */
    public static String chessListToFen(List<Chess> chessList) {
        // 第一次整理，将空白
        StringBuilder sb = new StringBuilder();
        for (int m = 0; m < 10; m++) {
            sb.append("/");
            for (int n = 0; n < 9; n++) {
                Chess chess = getChess(chessList, n, m);
                if (chess != null) {
                    sb.append(chess.getK());
                } else {
                    sb.append("z");
                }
            }
        }

        // 将连续的z整合为数字
        int j = 0;
        StringBuilder fen = new StringBuilder();
        for (int i = 0; i < sb.length(); i++) {
            final char c = sb.charAt(i);
            if (c == 'z') {
                j++;
            } else {
                if (j > 0) {
                    fen.append(j);
                    j = 0;
                }
                fen.append(c);
            }
        }
        if (j > 0) {
            fen.append(j);
        }
        final String s = fen.toString().replaceFirst("/", "");
        return s;
    }

    /**
     * 获得棋子
     *
     * @param chessList
     * @param x
     * @param y
     * @return
     */
    public static Chess getChess(List<Chess> chessList, int x, int y) {
        for (final Chess chess : chessList) {
            if (chess.getX() == x && chess.getY() == y) {
                return chess;
            }
        }
        return null;
    }

    /**
     * 获取棋子
     *
     * @param fen
     * @param x
     * @param y
     * @return
     */
    public static Chess getChess(String fen, int x, int y) {
        return getChess(FenUtils.fenToChessList(fen), x, y);
    }

    /**
     * 弹出棋子
     *
     * @param chessList
     * @param x
     * @param y
     * @return
     */
    public static Chess popChess(List<Chess> chessList, int x, int y) {
        for (int i = 0; i < chessList.size(); i++) {
            final Chess chess = chessList.get(i);
            if (chess.getX() == x && chess.getY() == y) {
                chessList.remove(i);
                return chess;
            }
        }
        return null;
    }

    /**
     * 将MOVE字符串转换为着法
     *
     * @param move 如:h9g7
     * @return
     */
    public static Zhao moveToZhao(String move) {
        int x1 = getIndexByZimu(move.charAt(0));
        int y1 = 9 - Integer.parseInt(move.substring(1, 2));
        int x2 = getIndexByZimu(move.charAt(2));
        int y2 = 9 - Integer.parseInt(move.substring(3, 4));
        Zhao zhao = new Zhao(x1, y1, x2, y2);
        zhao.setMove(move);
        return zhao;
    }

    public static void reverseZhao(Zhao zhao) {
        zhao.setX1(8 - zhao.getX1());
        zhao.setX2(8 - zhao.getX2());
        zhao.setY1(9 - zhao.getY1());
        zhao.setY2(9 - zhao.getY2());
    }

//    /**
//     * 将MOVE字符串指转换为着法列表
//     *
//     * @param moves
//     * @return
//     */
//    public static List<Zhao> movesToZhaoListBySpace(String moves) {
//        String[] s = moves.split(" ");
//        List<Zhao> zhaoList = new ArrayList<>();
//        for (String move : s) {
//            if (StrUtil.isNotBlank(move)) {
//                Zhao zhao = moveToZhao(move);
//                zhaoList.add(zhao);
//            }
//        }
//        return zhaoList;
//    }

    public static List<Zhao> numsToZhaoList(String nums) {
        final List<String> s = getListByLen(nums, 4);

        List<Chess> chessList = FenUtils.fenToChessList(null);
        boolean red = true;

        List<Zhao> zhaoList = new ArrayList<>();
        for (int i = 0; i < s.size(); i++) {
            String num = s.get(i);
            Zhao zhao = numToZhao(chessList, num);
            zhao.setRed(red);
            zhao.setIdx(i);
            red = !red;

            zhao.setName(ZhaoFaUtils.getZhaoFaName(zhao.getFen1(), FenUtils.zhaoToMove(zhao)));

            zhaoList.add(zhao);
        }
        return zhaoList;
    }

    private static Zhao numToZhao(List<Chess> chessList, String num) {
        if (StrUtil.isNotBlank(num)) {
            String[] split = num.split("");
            int x1 = Integer.parseInt(split[0]);
            int y1 = Integer.parseInt(split[1]);
            int x2 = Integer.parseInt(split[2]);
            int y2 = Integer.parseInt(split[3]);

            Zhao zhao = new Zhao(x1, y1, x2, y2);
            zhao.setFen1(FenUtils.chessListToFen(chessList));
            FenUtils.stepOne(chessList, zhao);
            zhao.setFen2(FenUtils.chessListToFen(chessList));

            return zhao;
        }
        return null;
    }

    private static void stepOne(List<Chess> chessList, Zhao zhao) {
        popChess(chessList, zhao.getX2(), zhao.getY2());
        Chess chess = getChess(chessList, zhao.getX1(), zhao.getY1());
        chess.setX(zhao.getX2());
        chess.setY(zhao.getY2());
    }

    /**
     * 着法转换为MOVE字符串
     *
     * @param zhao
     * @return 如:h9g7
     */
    public static String zhaoToMove(Zhao zhao) {
        final String[] ziArr = new String[]{"a", "b", "c", "d", "e", "f", "g", "h", "i"};
        final String s1 = ziArr[zhao.getX1()];
        final String s2 = String.valueOf(9 - zhao.getY1());
        final String s3 = ziArr[zhao.getX2()];
        final String s4 = String.valueOf(9 - zhao.getY2());
        return s1 + s2 + s3 + s4;
    }

    /**
     * 根据字符返回字符下标
     *
     * @param s
     * @return
     */
    private static int getIndexByZimu(char s) {
        final int[] ziArr = new int[]{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'};
        for (int i = 0; i < ziArr.length; i++) {
            if (ziArr[i] == s) {
                return i;
            }
        }
        return -1;
    }

    public static void getFen1Fen2(String fen, Zhao zhao) {
        getFen1Fen2(FenUtils.fenToChessList(fen), zhao);
    }

    public static void getFen1Fen2(List<Chess> chessList, Zhao zhao) {

        String fen1 = FenUtils.chessListToFen(chessList);
        zhao.setFen1(fen1);

        List<Chess> tempList = FenUtils.fenToChessList(fen1);

        popChess(tempList, zhao.getX2(), zhao.getY2());

        Chess chess = getChess(tempList, zhao.getX1(), zhao.getY1());
        zhao.setRed(chess.getType().equals("w"));

        try {
            chess.setX(zhao.getX2());
            chess.setY(zhao.getY2());
        } catch (Exception e) {
            e.printStackTrace();
        }
        zhao.setFen2(FenUtils.chessListToFen(tempList));
    }

    private static List<String> getListByLen(String s, int len) {
        List<String> list = new ArrayList<>();
        StringBuilder sb = new StringBuilder();
        int has = 0;
        for (int i = 0; i < s.length(); i++) {
            has++;
            sb.append(s.charAt(i));
            if (has == len) {
                list.add(sb.toString());
                sb = new StringBuilder();
                has = 0;
            }
        }
        return list;
    }

    public static List<Chess> copyChessList(List<Chess> chessList) {
        String fen = chessListToFen(chessList);
        return fenToChessList(fen);
    }

    public static Zhao eatOrMove(List<Chess> chessList, Chess click1, Chess c) {
        Zhao zhao = new Zhao(click1.getX(), click1.getY(), c.getX(), c.getY());
        zhao.setFen1(FenUtils.chessListToFen(chessList));
        zhao.setRed(click1.getType().equals("w"));

        zhao.setName(ZhaoFaUtils.getZhaoFaName(FenUtils.chessListToFen(chessList), FenUtils.zhaoToMove(zhao)));

        Chess chess = getChess(chessList, click1.getX(), click1.getY());
        popChess(chessList, c.getX(), c.getY());
        chess.setX(c.getX());
        chess.setY(c.getY());
        zhao.setFen2(FenUtils.chessListToFen(chessList));
        return zhao;
    }

    public static Zhao eatOrMove(List<Chess> chessList, Zhao zhao) {
        String fen1 = FenUtils.chessListToFen(chessList);
        zhao.setFen1(fen1);
        Chess chess1 = getChess(fen1, zhao.getX1(), zhao.getY1());
        Chess chess2 = new Chess();
        chess2.setX(zhao.getX2());
        chess2.setY(zhao.getY2());
        eatOrMove(chessList, chess1, chess2);
        return zhao;
    }

    public static String transe(String roundStr) {
        String[] split = roundStr.split("");
        StringBuilder sb = new StringBuilder();
        for (String s : split) {
            if (StrUtil.isNumeric(s)) {
                String s1 = map.get(s);
                sb.append(s1);
            } else {
                sb.append(s);
            }
        }
        return sb.toString();
    }
}